/*
REWRITTEN FROM SCRATCH BY PUSSYWIZARD, IT OWNS NOW!
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "oculus.h"
#include "SpellInfo.h"

enum Spells
{
	SPELL_EVOCATION = 51602,
	SPELL_SUMMON_MENAGERIE_1 = 50476,
	SPELL_SUMMON_MENAGERIE_2 = 50495,
	SPELL_SUMMON_MENAGERIE_3 = 50496,
	SPELL_TELEPORT = 51112,

	SPELL_FROSTBOMB = 51103,
	SPELL_TIME_BOMB_N = 51121,
	SPELL_TIME_BOMB_H = 59376,
	SPELL_EMPOWERED_ARCANE_EXPLOSION_N = 51110,
	SPELL_EMPOWERED_ARCANE_EXPLOSION_H = 59377,
};

#define SPELL_EMPOWERED_ARCANE_EXPLOSION		DUNGEON_MODE(SPELL_EMPOWERED_ARCANE_EXPLOSION_N, SPELL_EMPOWERED_ARCANE_EXPLOSION_H)
#define SPELL_TIME_BOMB							DUNGEON_MODE(SPELL_TIME_BOMB_N, SPELL_TIME_BOMB_H)

enum UromNPCs
{
	NPC_PHANTASMAL_CLOUDSCRAPER = 27645,
	NPC_PHANTASMAL_MAMMOTH = 27642,
	NPC_PHANTASMAL_WOLF = 27644,

	NPC_PHANTASMAL_AIR = 27650,
	NPC_PHANTASMAL_FIRE = 27651,
	NPC_PHANTASMAL_WATER = 27653,

	NPC_PHANTASMAL_MURLOC = 27649,
	NPC_PHANTASMAL_NAGAL = 27648,
	NPC_PHANTASMAL_OGRE = 27647,
};

enum Events
{
	EVENT_FROSTBOMB = 1,
	EVENT_TELEPORT_TO_CENTER = 2,
	EVENT_TELE_BACK = 3,
	EVENT_TIME_BOMB = 4,
};

enum Yells
{
	SAY_SUMMON_1 = 0,
	SAY_SUMMON_2 = 1,
	SAY_SUMMON_3 = 2,
	SAY_AGGRO = 3,
	EMOTE_ARCANE_EXPLOSION = 4,
	SAY_ARCANE_EXPLOSION = 5,
	SAY_DEATH = 6,
	SAY_PLAYER_KILL = 7
};

float summons[3][4] = {
	{ NPC_PHANTASMAL_AIR, NPC_PHANTASMAL_AIR, NPC_PHANTASMAL_WATER, NPC_PHANTASMAL_FIRE },
	{ NPC_PHANTASMAL_OGRE, NPC_PHANTASMAL_OGRE, NPC_PHANTASMAL_NAGAL, NPC_PHANTASMAL_MURLOC },
	{ NPC_PHANTASMAL_CLOUDSCRAPER, NPC_PHANTASMAL_CLOUDSCRAPER, NPC_PHANTASMAL_MAMMOTH, NPC_PHANTASMAL_WOLF }
};

float cords[4][4] = {
	{ 1177.47f, 937.722f, 527.405f, 2.21657f },
	{ 968.66f, 1042.53f, 527.32f, 0.077f },
	{ 1164.02f, 1170.85f, 527.321f, 3.66f },
	{ 1118.31f, 1080.377f, 508.361f, 4.25f }
};

class boss_urom : public CreatureScript
{
public:
	boss_urom() : CreatureScript("boss_urom") { }

	CreatureAI* GetAI(Creature* pCreature) const
	{
		return new boss_uromAI(pCreature);
	}

	struct boss_uromAI : public ScriptedAI
	{
		boss_uromAI(Creature *c) : ScriptedAI(c)
		{
			pInstance = c->GetInstanceScript();
		}

		InstanceScript* pInstance;
		EventMap events;
		bool lock;
		float x, y, z;
		int32 releaseLockTimer;

		uint8 GetPhaseByCurrentPosition()
		{
			for (uint8 i = 0; i < 4; ++i)
			if (me->GetDistance(cords[i][0], cords[i][1], cords[i][2]) < 20.0f)
				return i;

			return 0;
		}

		void Reset()
		{
			if (pInstance)
			{
				pInstance->SetData(DATA_UROM, NOT_STARTED);
				if (pInstance->GetData(DATA_VAROS) != DONE)
					me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
				else
					me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
			}

			me->CastSpell(me, SPELL_EVOCATION, true);
			events.Reset();
			lock = false;
			x, y, z = 0.0f;
			releaseLockTimer = 0;
			me->ApplySpellImmune(0, IMMUNITY_ID, 49838, true);
		}

		void EnterCombat(Unit* /*who*/)
		{
			if (lock)
				return;

			uint8 phase = GetPhaseByCurrentPosition();
			if (phase == 3)
			{
				Talk(SAY_AGGRO);

				if (pInstance)
					pInstance->SetData(DATA_UROM, IN_PROGRESS);

				me->SetInCombatWithZone();
				me->SetHomePosition(cords[0][0], cords[0][1], cords[0][2], cords[0][3]);
				if (me->FindCurrentSpellBySpellId(SPELL_EVOCATION))
					me->InterruptNonMeleeSpells(false);

				events.RescheduleEvent(EVENT_FROSTBOMB, urand(7000, 11000));
				events.RescheduleEvent(EVENT_TELEPORT_TO_CENTER, urand(30000, 35000));
				events.RescheduleEvent(EVENT_TIME_BOMB, urand(20000, 25000));
			}
			else
			{
				lock = true;

				switch (phase)
				{
				case 0:
					Talk(SAY_SUMMON_1);
					me->InterruptNonMeleeSpells(false);
					me->CastSpell(me, SPELL_SUMMON_MENAGERIE_1, false);
					break;
				case 1:
					Talk(SAY_SUMMON_2);
					me->InterruptNonMeleeSpells(false);
					me->CastSpell(me, SPELL_SUMMON_MENAGERIE_2, false);
					break;
				case 2:
					Talk(SAY_SUMMON_3);
					me->InterruptNonMeleeSpells(false);
					me->CastSpell(me, SPELL_SUMMON_MENAGERIE_3, false);
					break;
				}
			}
		}

		void AttackStart(Unit* who)
		{
			if (lock)
				return;

			if (me->GetDistance(1103.0f, 1049.0f, 510.0f) < 55.0f)
				ScriptedAI::AttackStart(who);
		}

		void JustSummoned(Creature* pSummon)
		{
			pSummon->SetInCombatWithZone();
			if (Unit* v = pSummon->SelectVictim())
			if (pSummon->AI())
				pSummon->AI()->AttackStart(v);
		}

		void LeaveCombat()
		{
			me->RemoveAllAuras();
			me->DeleteThreatList();
			me->CombatStop(true);
			me->LoadCreaturesAddon(true);
			me->SetLootRecipient(NULL);
			me->ResetPlayerDamageReq();
		}

		void JustDied(Unit* /*killer*/)
		{
			Talk(SAY_DEATH);

			if (pInstance)
				pInstance->SetData(DATA_UROM, DONE);
		}

		void KilledUnit(Unit* /*victim*/)
		{
			Talk(SAY_PLAYER_KILL);
		}

		void SpellHit(Unit* /*caster*/, const SpellInfo* spell)
		{
			switch (spell->Id)
			{
			case SPELL_SUMMON_MENAGERIE_1:
			{
											 for (uint8 i = 0; i < 4; ++i)
												 me->SummonCreature(summons[0][i], cords[0][0] + ((i % 2) ? 4.0f : -4.0f), cords[0][1] + (i < 2 ? 4.0f : -4.0f), cords[0][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN, 300000);
											 uint8 phase = GetPhaseByCurrentPosition();
											 me->SetHomePosition(cords[phase + 1][0], cords[phase + 1][1], cords[phase + 1][2], cords[phase + 1][3]);
											 me->DestroyForNearbyPlayers();
											 LeaveCombat();
											 me->CastSpell(me, SPELL_EVOCATION, true);
											 releaseLockTimer = 1;
			}
				break;
			case SPELL_SUMMON_MENAGERIE_2:
			{
											 for (uint8 i = 0; i < 4; ++i)
												 me->SummonCreature(summons[1][i], cords[1][0] + ((i % 2) ? 4.0f : -4.0f), cords[1][1] + (i < 2 ? 4.0f : -4.0f), cords[1][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN, 300000);
											 uint8 phase = GetPhaseByCurrentPosition();
											 me->SetHomePosition(cords[phase + 1][0], cords[phase + 1][1], cords[phase + 1][2], cords[phase + 1][3]);
											 me->DestroyForNearbyPlayers();
											 LeaveCombat();
											 me->CastSpell(me, SPELL_EVOCATION, true);
											 releaseLockTimer = 1;
			}
				break;
			case SPELL_SUMMON_MENAGERIE_3:
			{
											 for (uint8 i = 0; i < 4; ++i)
												 me->SummonCreature(summons[2][i], cords[2][0] + ((i % 2) ? 4.0f : -4.0f), cords[2][1] + (i < 2 ? 4.0f : -4.0f), cords[2][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN, 300000);
											 uint8 phase = GetPhaseByCurrentPosition();
											 me->SetHomePosition(cords[phase + 1][0], cords[phase + 1][1], cords[phase + 1][2], cords[phase + 1][3]);
											 me->DestroyForNearbyPlayers();
											 LeaveCombat();
											 me->CastSpell(me, SPELL_EVOCATION, true);
											 releaseLockTimer = 1;
			}
				break;
			case SPELL_TELEPORT:
				me->GetMotionMaster()->Clear();
				me->GetMotionMaster()->MoveIdle();
				me->StopMoving();
				me->SetControlled(true, UNIT_STATE_ROOT);
				me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
				me->SetCanFly(true);
				me->SetDisableGravity(true);
				me->NearTeleportTo(1103.69f, 1048.76f, 512.279f, 1.16f);

				Talk(SAY_ARCANE_EXPLOSION);
				Talk(EMOTE_ARCANE_EXPLOSION);

				me->CastSpell(me, SPELL_EMPOWERED_ARCANE_EXPLOSION, false);
				events.RescheduleEvent(EVENT_TELE_BACK, DUNGEON_MODE(9000, 7000));
			default:
				break;
			}
		}

		void MoveInLineOfSight(Unit* /*who*/) {}

		void UpdateAI(uint32 diff)
		{
			if (releaseLockTimer)
			{
				if (releaseLockTimer >= 5000)
				{
					lock = false;
					if (me->IsInCombat())
					{
						LeaveCombat();
						me->CastSpell(me, SPELL_EVOCATION, true);
					}
					releaseLockTimer = 0;
				}
				else
					releaseLockTimer += diff;
			}

			if (!UpdateVictim())
				return;

			events.Update(diff);

			if (me->HasUnitState(UNIT_STATE_CASTING))
				return;

			DoMeleeAttackIfReady();

			switch (events.GetEvent())
			{
			case 0:
				break;
			case EVENT_FROSTBOMB:
				if (Unit* v = me->GetVictim())
					me->CastSpell(v, SPELL_FROSTBOMB, false);
				events.RepeatEvent(urand(7000, 11000));
				break;
			case EVENT_TIME_BOMB:
				if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
					me->CastSpell(target, SPELL_TIME_BOMB, false);
				events.RepeatEvent(urand(20000, 25000));
				break;
			case EVENT_TELEPORT_TO_CENTER:
				x = me->GetPositionX();
				y = me->GetPositionY();
				z = me->GetPositionZ();
				me->CastSpell(me, SPELL_TELEPORT, false);
				events.RepeatEvent(urand(25000, 30000));
				events.DelayEvents(10000);
				break;
			case EVENT_TELE_BACK:
				me->GetMotionMaster()->MoveIdle();
				me->DisableSpline();
				me->SetCanFly(false);
				me->SetDisableGravity(false);
				me->NearTeleportTo(x, y, z, 0.0f);
				me->SetControlled(false, UNIT_STATE_ROOT);
				me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
				me->GetMotionMaster()->MoveChase(me->GetVictim());
				events.PopEvent();
				break;
			}
		}

		void EnterEvadeMode()
		{
			me->SetCanFly(false);
			me->SetDisableGravity(false);
			me->SetControlled(false, UNIT_STATE_ROOT);
			ScriptedAI::EnterEvadeMode();
		}
	};
};

void AddSC_boss_urom()
{
	new boss_urom();
}
